﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.Collections.ObjectModel;
using System.Globalization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using DnDCharacterBuilder.Windows;
using DnDCharacterBuilder.Data;


namespace DnDCharacterBuilder
{

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        # region Props
        CharacterData dc = new CharacterData();
        ReferenceWindow rWin;
        Options optWin;

        private ObservableCollection<FileTag> fileList = new ObservableCollection<FileTag>() { };
        public ObservableCollection<FileTag> FileList
        {
            get { return fileList; }
            set
            {
                fileList = value;
            }
        }

        # endregion

        public MainWindow()
        {
            InitializeComponent();
            DataContext = dc;
            OpenFileList.DataContext = this;

        }

        # region Commands


        //protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        //{
        //    // Check for open windows
        //    if (rWin.IsLoaded)
        //        rWin.Close();
        //    if (optWin.IsLoaded)
        //        optWin.Close();

        //    base.OnClosing(e);
        //}

        private void CloseCommand(object sender, ExecutedRoutedEventArgs e)
        {
            
            this.Close();
        }

        private void Class_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // #do not like
            //if (ClassSelection.SelectedValue == "Cleric")
            //    dc.CurrHealth = new ClericClass().HealthInit + dc.Con + ((dc.Level - 1) * new ClericClass().HealthPerLevel);
            //else if (ClassSelection.SelectedValue == "Fighter")
            //    dc.CurrHealth = new FighterClass().HealthInit + dc.Con + ((dc.Level - 1) * new FighterClass().HealthPerLevel);
            //else if (ClassSelection.SelectedValue == "Paladin")
            //    dc.CurrHealth = new PaladinClass().HealthInit + dc.Con + ((dc.Level - 1) * new PaladinClass().HealthPerLevel);
            //else if (ClassSelection.SelectedValue == "Ranger")
            //    dc.CurrHealth = new RangerClass().HealthInit + dc.Con + ((dc.Level - 1) * new RangerClass().HealthPerLevel);
            //else if (ClassSelection.SelectedValue == "Rogue")
            //    dc.CurrHealth = new RogueClass().HealthInit + dc.Con + ((dc.Level - 1) * new RogueClass().HealthPerLevel);
            //else if (ClassSelection.SelectedValue == "Warlock")
            //    dc.CurrHealth = new WarlockClass().HealthInit + dc.Con + ((dc.Level - 1) * new WarlockClass().HealthPerLevel);
            //else if (ClassSelection.SelectedValue == "Warlord")
            //    dc.CurrHealth = new WarlordClass().HealthInit + dc.Con + ((dc.Level - 1) * new WarlordClass().HealthPerLevel);
            //else if (ClassSelection.SelectedValue == "Wizard")
            //    dc.CurrHealth = new WizardClass().HealthInit + dc.Con + ((dc.Level - 1) * new WizardClass().HealthPerLevel);
            
            ////charClass.HealthInit + Con + ((Level - 1) * charClass.HealthPerLevel)
            //dc.Update();
        }

        private void TryToAddToFileList(string path, string tag)
        {
            // Check for previously existing in list
            foreach (FileTag f in FileList)
                if (f.FilePath == path || f.Tag == tag)
                    return;

            // If not matches, add to list
            FileList.Add(new FileTag(path, tag));
        }

        public void Save(object sender, ExecutedRoutedEventArgs e)
        {
            Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
            dlg.FileName = "Document";
            dlg.DefaultExt = ".xml";
            dlg.Filter = "eXtensible Markup Language (.xml)|*.xml";
            Nullable<bool> result = dlg.ShowDialog();

            if (result == true)
            {
                try
                {
                    SerializeToXML(dc, dlg.FileName);
                    StatusBarLabel.Content = "Saved to " + dlg.FileName + ".";
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Failed to save.\n" + ex.Message, "Save error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        public void LoadHandler(object sender, ExecutedRoutedEventArgs e)
        {
            Load();
        }
        public void Load(string path="")
        {
            bool addToList = false;
            if (path == "")
            {
                addToList = true;
                Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
                dlg.FileName = "Document";
                dlg.DefaultExt = ".xml";
                dlg.Filter = "eXtensible Markup Language (.xml)|*.xml";
                Nullable<bool> result = dlg.ShowDialog();
                if (result == true)
                    path = dlg.FileName;
            }
            if (path != "" && path != null)
            {                
                try
                {
                    dc = DeserializeFromXML(path);
                    dc.Update();
                    DataContext = dc;
                    StatusBarLabel.Content = "Loaded from " + path + ".";
                    if (addToList)
                    {
                        string[] t = path.Split('\\');
                        string tag = t.Last();
                        tag = tag.Split('.').First();
                        TryToAddToFileList(path, tag);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Failed to load data.\n" + ex.Message, "Load error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
            
        }

        public void ResetHandler(object sender, ExecutedRoutedEventArgs e)
        {
            Reset();
        }
        public void Reset()
        {
            dc = new CharacterData();
            dc.Update();
            DataContext = dc; 
        }

        private void SettingsHandler(object sender, ExecutedRoutedEventArgs e)
        {
            if (optWin == null || !optWin.IsLoaded)
            {
                optWin = new Options();
                optWin.Owner = this;
                optWin.Show();
            }
            
            if (!optWin.IsFocused)
                optWin.Focus();
        }

        public void SerializeToXML(CharacterData cd, string fp)
        {
            IFormatter formatter = new BinaryFormatter();

            using (FileStream stream = new FileStream(fp, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                formatter.Serialize(stream, cd);
            }
        }
        public CharacterData DeserializeFromXML(string fp)
        {
            IFormatter formatter = new BinaryFormatter();
            using (FileStream stream = new FileStream(fp, FileMode.Open, FileAccess.Read, FileShare.None))
            {
                return (CharacterData)formatter.Deserialize(stream);
            }
        }

        private void Window_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            StatusBarLabel.Content = "";
        }

        #endregion

        #region Box Commands
        private void LanguageBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ObservableCollection<string> temp = new ObservableCollection<string>();
            foreach (string s in LanguageBox.SelectedItems)
                temp.Add(s);
            dc.SelectedLanguages = temp;
            dc.Update();
        }

        private void MoveFileUp_Click(object sender, RoutedEventArgs e)
        {
            if (OpenFileList.SelectedIndex > 0)
                FileList.Move(OpenFileList.SelectedIndex, OpenFileList.SelectedIndex - 1);
        }

        private void AddFile_Click(object sender, RoutedEventArgs e)
        {
            Load();
        }

        private void RemoveFile_Click(object sender, RoutedEventArgs e)
        {
            int currIndex = OpenFileList.SelectedIndex;
            if (OpenFileList.SelectedIndex >= 0)
                FileList.RemoveAt(OpenFileList.SelectedIndex);
            if (currIndex < OpenFileList.Items.Count)
                OpenFileList.SelectedIndex = currIndex;
            else
                OpenFileList.SelectedIndex = OpenFileList.Items.Count - 1;
            if (OpenFileList.Items.Count == 0)
                Reset();
        }

        private void MoveFileDown_Click(object sender, RoutedEventArgs e)
        {
            if (OpenFileList.SelectedIndex < OpenFileList.Items.Count - 1)
                FileList.Move(OpenFileList.SelectedIndex, OpenFileList.SelectedIndex + 1);
        }

        private void OpenFileList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (OpenFileList.SelectedIndex >= 0)
                Load(path: ((FileTag)OpenFileList.SelectedItem).FilePath);
        }

        private void AddGold_Click(object sender, RoutedEventArgs e)
        {
            dc.CharMoney += dc.DiffMoney;
            dc.DiffMoney = new Money();
        }

        private void SubGold_Click(object sender, RoutedEventArgs e)
        {
            dc.CharMoney -= dc.DiffMoney;
            dc.DiffMoney = new Money();
        }

        private void ToggleRef_Click(object sender, RoutedEventArgs e)
        {
            // If null, close and start over
            if (rWin != null)
            {
                rWin.Close();
                rWin = null;
            }
            
            // Create new window (or attempt to)
            rWin = new ReferenceWindow();
            
            // If not null, open and show
            if (rWin != null)
            {
                rWin.Owner = this;
                rWin.Show();

                if (!rWin.IsFocused)
                    rWin.Focus();
            }         

        }


        #endregion

        

    }

    public class FileTag
    {
        public string FilePath { set; get; }
        public string Tag { set; get; }

        public FileTag(string fp, string t)
        {
            FilePath = fp;
            Tag = t;
        }

        public override bool Equals(object obj)
        {
            if (typeof(object) == typeof(FileTag))
            {
                FileTag comp = (FileTag)obj;
                if (comp.FilePath == FilePath && comp.Tag == Tag)
                    return true;
            }
            return false;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

    [ValueConversion(typeof(int), typeof(string))]
    public class ModConversion : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return string.Format("({0})", value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    [ValueConversion(typeof(int), typeof(string))]
    public class Int2String : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((int)value).ToString();
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            int i;
            if (!(int.TryParse((string)value, out i)))
                return 0;
            else
                return i; 
        }
    }

    //[ValueConversion(typeof(DataGrid), typeof(int))]
    //public class AttackBonusConv : IValueConverter
    //{
    //    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    //    {
    //        EquipmentData.WeaponsDataTable wp = (EquipmentData.WeaponsDataTable)value;
    //        return 10;
    //    }

    //    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    //    {
    //        throw new NotImplementedException();
    //    }
    //}

}
